#include "common.h"
#include "gui.h"
#include "TAMC_GT911.h"
#include "scr_st7701_4inch_square.h"
#include "lvgl.h"

static TAMC_GT911 tp = TAMC_GT911(TOUCH_SDA, TOUCH_SCL, TOUCH_INT, TOUCH_RST, SCREEN_RES_HOR, SCREEN_RES_VER);
static lv_color_t *disp_draw_buf;
static lv_color_t *disp_draw_buf2;
static lv_disp_draw_buf_t draw_buf;
static lv_disp_drv_t disp_drv;
static lv_indev_t *indev_touchpad;

static void flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
  uint32_t w = (area->x2 - area->x1 + 1);
  uint32_t h = (area->y2 - area->y1 + 1);
  gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h);
  lv_disp_flush_ready(disp);
}

static void scr_lvgl_init() {
  size_t lv_cache_rows = 120;
  disp_draw_buf = (lv_color_t *)heap_caps_malloc(lv_cache_rows * SCREEN_RES_HOR * 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
  lv_init();
  lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, NULL, SCREEN_RES_HOR * lv_cache_rows);
  lv_disp_drv_init(&disp_drv);
  disp_drv.hor_res = SCREEN_RES_HOR;
  disp_drv.ver_res = SCREEN_RES_VER;
  disp_drv.flush_cb = flush_callback;
  disp_drv.draw_buf = &draw_buf;
  lv_disp_drv_register(&disp_drv);
}

static void scr_pre_init() {
  gfx = new Arduino_RGB_Display(
    480, 480, rgbpanel, 0, true,
    bus, GFX_NOT_DEFINED, st7701_type1A_init_operations, sizeof(st7701_type1A_init_operations));

  gfx->begin(12000000L);
  delay(100);
}

static void touchpad_init(void) {
  tp.begin();
  tp.setRotation(ROTATION_INVERTED);
}

static void touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
  tp.read();
  if (tp.isTouched) {
    for (int i = 0; i < tp.touches; i++) {

      if (tp.points[i].x > 0 && tp.points[i].x <= SCREEN_RES_HOR)
        data->point.y = SCREEN_RES_HOR - tp.points[i].x - 1;
      if (tp.points[i].y > 0 && tp.points[i].y <= SCREEN_RES_VER)
        data->point.x = tp.points[i].y - 1;
    }
    data->point.x = tp.points[0].x;
    data->point.y = tp.points[0].y;
    data->state = LV_INDEV_STATE_PR;
  } else {
    data->state = LV_INDEV_STATE_REL;
  }
}

void gfx_pre_init() {
  touchpad_init();
  scr_pre_init();
}

static void indev_init() {
  static lv_indev_drv_t indev_drv;
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = touchpad_read;
  indev_touchpad = lv_indev_drv_register(&indev_drv);
}

void task_lvgl(void *pvParameters) {
  scr_lvgl_init();
  indev_init();
  MY_INFO("LVGL Init complete.\n");
  load_ui();
  uint32_t task_delay_ms = 1;
  for (;;) {
    task_delay_ms = lv_task_handler();
    task_delay_ms = constrain(task_delay_ms, 2, 10);
    vTaskDelay(pdMS_TO_TICKS(task_delay_ms));
  }
}
